<?php

/**
 * @author      Nguyen Duc Thuan <me@ndthuan.com>
 * @copyright   Copyright (c) 2009 Nguyen Duc Thuan <me@ndthuan.com>
 * @version     $Id: Image.php 12 2009-11-03 03:17:46Z thuan.nguyen $
 */

class Fete_Image
{
    /**
     * Errors
     *
     * @var array
     */
    protected $_errors = array();

    /**
     * Image path
     *
     * @var string
     */
    protected $_path = null;

    /**
     * Image width
     *
     * @var integer
     */
    protected $_width = 0;

    /**
     * Image height
     *
     * @var integer
     */
    protected $_height = 0;

    /**
     * Image MIME type
     *
     * @var string
     */
    protected $_mimeType = 'undefined';

    /**
     * Bytes of image file
     *
     * @var integer
     */
    protected $_fileSize = 0;

    /**
     * Image resource
     *
     * @var resource
     */
    protected $_imageResource = null;

    /**
     * Image's binary content
     *
     * @var string
     */
    protected $_binContents = null;

    /**
     * This class' supported types
     *
     * @var array
     */
    protected $_supportedTypes = array('image/jpeg', 'image/gif', 'image/png');

    /**
     * Construct new Fete_Image object
     *
     * @return Fete_Image
     */
    public function __construct($filePath = '')
    {
        if ('' !== $filePath) {
            $this->loadImage($filePath);
        }
    }

    /**
     * Load image
     *
     * @param string $filePath
     * @return Fete_Image
     */
    public function &loadImage($filePath)
    {
        if (!extension_loaded('gd')) {
            $this->_errors[] = 'GD library is not loaded';
        }

        $this->_path = $filePath;

        if (($info = @getimagesize($filePath))) {
            $this->_width       = $info[0];
            $this->_height      = $info[1];
            $this->_mimeType    = $info['mime'];
            $this->_fileSize    = filesize($filePath);

            if (!$this->isSupported()) {
                $this->_errors[] = 'Your image type is currently '
                    . 'not supported by this class :D';
            } else {
                $this->_loadImage();
            }

        } else {

            $this->_errors[] = 'Could not get image info';
        }

        return $this;
    }

    /**
     * Resize image by width/height limits and keep their ratio
     *
     * @param integer $widthLimit
     * @param integer $heightLimit
     * @return Fete_Image
     */
    public function &resizeByLimits($widthLimit = null, $heightLimit = null)
    {
        $ratio = 1;

        if ($widthLimit !== null && $widthLimit > 0) {
            $ratio  = $widthLimit / $this->_width;
        }

        if ($ratio * $this->_height > $heightLimit
            && $heightLimit !== null
            && $heightLimit > 0) {

            $ratio  = $heightLimit / $this->_height;
        }

        $this->resizeByRatio($ratio);

        return $this;
    }

    /**
     * Resize iamge by ratio
     *
     * @param float $ratio
     * @return Fete_Image
     */
    public function &resizeByRatio($ratio)
    {
        $this->resizeTo($this->_width * $ratio, $this->_height * $ratio);

        return $this;
    }

    /**
     * Resize image to desired width and height
     *
     * @param integer $width
     * @param integer $height
     * @return Fete_Image
     */
    public function &resizeTo($width, $height)
    {
        $width  = round($width);
        $height = round($height);

        $newImage = imagecreatetruecolor($width, $height);

        if ('image/gif' === $this->_mimeType || 'image/png' === $this->_mimeType) {
            $colorCount = imagecolorstotal($this->_imageResource);

            if (0 === $colorCount) {
                $colorCount = 256;
            }

            imagetruecolortopalette($newImage, true, $colorCount);
            imagepalettecopy($newImage, $this->_imageResource);
            $transparentColor = imagecolortransparent($this->_imageResource);
            imagefill($newImage, 0, 0, $transparentColor);
            imagecolortransparent($newImage, $transparentColor);
        }

        @imagecopyresampled(
            $newImage,
            $this->_imageResource,
            0,
            0,
            0,
            0,
            $width,
            $height,
            $this->_width,
            $this->_height);

        ob_start();
        switch ($this->_mimeType)
        {
            case 'image/jpeg':
                imagejpeg($newImage, null, 100);
                break;
            case 'image/gif':
                imagegif($newImage);
                break;
            case 'image/png':
                imagepng($newImage);
                break;
            default:
                return $this;
                break;
        }
        $this->_binContents = ob_get_clean();

        imagedestroy($newImage);

        $this->_width       = $width;
        $this->_height      = $height;
        $this->_fileSize    = strlen($this->_binContents);

        return $this;
    }

    /**
     * Crops image
     *
     * @param integer $sourceX
     * @param integer $sourceY
     * @param integer $destWidth
     * @param integer $destHeight
     * @return Fete_Image
     */
    public function &crop($sourceX, $sourceY, $destWidth, $destHeight)
    {
        $newImage = imagecreatetruecolor($destWidth, $destHeight);
        $srcImage = imagecreatefromstring($this->_binContents);

        imagecopy(
            $newImage,
            $srcImage,
            0,
            0,
            $sourceX,
            $sourceY,
            $destWidth,
            $destHeight);


        ob_start();
        switch ($this->_mimeType)
        {
            case 'image/jpeg':
                imagejpeg($newImage, null, 100);
                break;
            case 'image/gif':
                imagegif($newImage);
                break;
            case 'image/png':
                imagepng($newImage);
                break;
            default:
                return false;
                break;
        }
        $this->_binContents = ob_get_clean();

        imagedestroy($newImage);
        imagedestroy($srcImage);

        $this->_width       = $destWidth;
        $this->_height      = $destHeight;
        $this->_fileSize    = strlen($this->_binContents);

        return $this;
    }

    /**
     * Save image into desired path
     *
     * @param string $filePath
     * @return Fete_Image
     */
    public function &saveTo($filePath)
    {
        $fp = fopen($filePath, 'w');
        @fwrite($fp, $this->_binContents);
        fclose($fp);

        $this->_path = $filePath;

        return $this;
    }

    /**
     * Save image into itself
     * @return Fete_Image
     */
    public function &save()
    {
        $this->saveTo($this->_path);
        return $this;
    }

    /**
     * Render image content
     *
     */
    public function render()
    {
        header("Content-Type: $this->_mimeType");
        echo $this->_binContents;
        exit;
    }

    /**
     * Destroy image resource
     * @return Fete_Image
     */
    public function &close()
    {
        imagedestroy($this->_imageResource);
        return $this;
    }

    public function getFilePath()
    {
        return $this->_path;
    }

    /**
     * Get image binary contents
     *
     * @return string
     */
    public function getBinContents()
    {
        return $this->_binContents;
    }

    /**
     * Get image file size in bytes
     *
     * @return integer
     */
    public function getFileSize()
    {
        return $this->_fileSize;
    }

    /**
     * Get MIME type of image
     *
     * @return string
     */
    public function getMimeType()
    {
        return $this->_mimeType;
    }

    /**
     * Gets Image File Extension
     *
     * @return string
     */
    public function getExtension()
    {
        switch ($this->_mimeType)
        {
            case 'image/jpeg':
                return 'jpg';
            case 'image/gif':
                return 'gif';
            case 'image/png':
                return 'png';
        }
    }

    /**
     * Get image width in pixels
     *
     * @return integer
     */
    public function getWidth()
    {
        return $this->_width;
    }

    /**
     * Get image height in pixels
     *
     * @return integer
     */
    public function getHeight()
    {
        return $this->_height;
    }

    /**
     * Get error info.
     *
     * @return array
     */
    public function getErrors()
    {
        return $this->_errors;
    }

    /**
     * Check if this image type is supported or not
     *
     * @return boolean
     */
    public function isSupported()
    {
        if (in_array($this->_mimeType, $this->_supportedTypes)) {
            return true;
        }

        return false;
    }

    /**
     * Check to see the instance has error(s) or not
     *
     * @return boolean
     */
    public function hasError()
    {
        if (count($this->_errors) > 0) {
            return true;
        }

        return false;
    }

    /**
     * Load image resource
     *
     */
    protected function _loadImage()
    {
        switch ($this->_mimeType)
        {
            case 'image/jpeg':
                $this->_imageResource = imagecreatefromjpeg($this->_path);
                break;
            case 'image/gif':
                $this->_imageResource = imagecreatefromgif($this->_path);
                break;
            case 'image/png':
                $this->_imageResource = imagecreatefrompng($this->_path);
                break;
        }

        $this->_binContents = file_get_contents($this->_path);
    }
}
